// serial_interface.cpp
#include "serial_interface.h"
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <system_error>
#include <iostream>

SerialInterface::SerialInterface() :fd_(-1){}

SerialInterface::~SerialInterface() {
    close();
}

bool SerialInterface::open(const std::string& port, int baud_rate) {
    std::lock_guard<std::mutex> lock(mutex_);
    if (is_open()) {
        close();
    }

    fd_ = ::open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd_ < 0) {
        // throw std::system_error(errno, std::system_category(), "Failed to open serial port");
        std::cout<<"Failed to open serial port"<<std::endl;
        return false;
    }
    
    if (!set_serial_attributes(baud_rate)) {
        close();
        return false;
    }
    
    flush_buffers();  // 清除可能的旧数据
    std::cout << "Serial port opened: fd=" << fd_ << std::endl;
    return true;
}
void SerialInterface::close() {
    std::lock_guard<std::mutex> lock(mutex_);
    if (fd_ != -1) {
        flush_buffers();
        ::close(fd_);
        fd_ = -1;
    }
}

bool SerialInterface::is_open() const {
    return fd_ != -1;
}

bool SerialInterface::is_healthy() const
{
    if (fd_ == -1) return false;
    uint8_t dummy{};
    int rc = ::read(fd_, &dummy, 0);   // 0 字节探测
    if (rc < 0 && (errno == EBADF || errno == ENODEV || errno == EIO))
        return false;                  // 已挂
    return true;
}

ssize_t SerialInterface::write(const uint8_t* data, size_t length) {
    std::lock_guard<std::mutex> lock(mutex_);
    if (!is_open()) {
        return -1;
    }
    
    size_t total_written = 0;
    while (total_written < length) {
        ssize_t written = ::write(fd_, data + total_written, length - total_written);
        if (written < 0) {
            if (errno == EINTR) continue;  // 中断重试
            return written;
        }
        total_written += written;
    }
    return total_written;
}

ssize_t SerialInterface::read(uint8_t* dst, size_t max_len)
{
    std::lock_guard<std::mutex> g(mutex_);
    if (fd_ < 0) return -1;

    fd_set rfds;
    struct timeval tv;
    size_t  total = 0;

    /* 第一次等待：给硬件一点 turnaround 时间 */
    tv.tv_sec  = 0;
    tv.tv_usec = 500000;          // 500 ms 足够 485 切换
    FD_ZERO(&rfds);
    FD_SET(fd_, &rfds);

    if (select(fd_ + 1, &rfds, nullptr, nullptr, &tv) <= 0)
        return 0;                 // 超时，确实没数据

    /* 第二次：把当前已到达的字节全部读完 */
    while (total < max_len) {
        ssize_t n = ::read(fd_, dst + total, max_len - total);
        if (n > 0) {
            total += n;
            /* 再试一次，直到把“刚刚又到达的”也拿光 */
            continue;
        }
        if (n == 0) break;        // EOF
        if (errno == EAGAIN || errno == EINTR)
            break;                // 缓冲区已空
        return -1;                // 真正出错
    }
    return total;
}

bool SerialInterface::set_serial_attributes(int baud_rate) {
    struct termios options;
    std::memset(&options, 0, sizeof(options));
    
    if (tcgetattr(fd_, &options) != 0) {
        return false;
    }
    
    cfsetispeed(&options, get_baud_code(baud_rate));
    cfsetospeed(&options, get_baud_code(baud_rate));
    
    options.c_cflag &= ~PARENB;      // 无奇偶校验
    options.c_cflag &= ~CSTOPB;      // 1位停止位,若设为 CSTOPB 则表示 2 位停止位
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;          // 8位数据位
    options.c_cflag |= (CLOCAL | CREAD); // 本地连接 | 接收使能
    
    // 原始输入模式：无回显，无信号处理
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_oflag &= ~OPOST;       // 原始输出
    options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | INLCR | IGNCR); // 禁用所有“回车/换行”映射与流控，确保 0x0D/0x0A 原样收发
    
    // 配置超时：设置500ms超时 (VTIME单位=0.1秒)
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 5;
    
    if (tcsetattr(fd_, TCSANOW, &options) != 0) {
        return false;
    }
    
    return true;
}


int SerialInterface::get_baud_code(int baud_rate) const {
    switch (baud_rate) {
        case 9600:    return B9600;
        case 19200:   return B19200;
        case 38400:   return B38400;
        case 57600:   return B57600;
        case 115200:  return B115200;
        case 230400:  return B230400;
        case 460800:  return B460800;
        case 500000:  return B500000;
        case 576000:  return B576000;
        case 921600:  return B921600;
        case 1000000: return B1000000;
        default:      return B115200;
    }
}

void SerialInterface::flush_buffers() {
    if (fd_ != -1) {
        tcflush(fd_, TCIOFLUSH);  // 清除输入/输出缓冲区
    }
}